﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Activation;
using System.Runtime.Remoting.Contexts;
using System.Runtime.Remoting.Messaging;
using System.Text;

namespace Luminji.Core.Enterprise.Aop
{
    public class SecurityAspect : IMessageSink
    {
        internal SecurityAspect(IMessageSink next)
        {
            _next = next;
        }

        private IMessageSink _next;

        public IMessageSink NextSink
        {
            get { return _next; }
        }

        public IMessage SyncProcessMessage(IMessage msg)
        {
            Preprocess(msg);
            IMessage returnMethod = _next.SyncProcessMessage(msg);
            return returnMethod;
        }

        public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
        {
            throw new InvalidOperationException();
        }

        private void Preprocess(IMessage msg)
        {
            if (!(msg is IMethodMessage))
                return;
            IMethodMessage call = msg as IMethodMessage;
            Type type = Type.GetType(call.TypeName);
            string callStr = type.Name + "." + call.MethodName;
            Console.WriteLine("Security validating : {0} for {1}", callStr,
                Environment.UserName);
            // call some security validating code
        }

    }

    public class SecurityProperty : IContextProperty, IContributeObjectSink
    {
        public IMessageSink GetObjectSink(MarshalByRefObject o, IMessageSink next)
        {
            return new SecurityAspect(next);
        }

        public string Name
        {
            get { return "SecurityProperty"; }
        }
        public void Freeze(Context newContext)
        {
        }
        public bool IsNewContextOK(Context newCtx)
        {
            return true;
        }
    }

    [AttributeUsage(AttributeTargets.All)]
    public class SecurityAttribute : ContextAttribute
    {
        public SecurityAttribute() : base("Security") { }
        public override void GetPropertiesForNewContext(IConstructionCallMessage ccm)
        {
            ccm.ContextProperties.Add(new SecurityProperty());
        }
    }
}
